using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Core;

namespace SupportGenerator
{
	public class DeserializeGenerator
	{
		private const string DAO_SUPPORT_DIRECTORY = @"GeneratedFiles\Support\Request\";
		private const string DATETIME_PARSE_TEMPLATE = @"				DateTime {PROPERTY_LOWER};
				if(DateTime.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER})) {
					{SEARCH_NAME}.{PROPERTY} = {PROPERTY_LOWER};
				}";

		private const string DESERILIZE_CLASS_WRAPPER =
			@"using System;
using {NAMESPACE_MODEL};
using Triton.Controller.Request;

namespace {NAMESPACE}
{
	public class Deserialize
	{
	
{NESTED_CLASSES}

	}
}";

		private const string FLOAT_PARSE_TEMPLATE = @"				float {PROPERTY_LOWER};
				{SEARCH_NAME}.{PROPERTY} = float.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER}) ? {PROPERTY_LOWER} : 0;";

		private const string INT_PARSE_TEMPLATE = @"				int {PROPERTY_LOWER};
				{SEARCH_NAME}.{PROPERTY} = int.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER}) ? {PROPERTY_LOWER} : 0;";

		private const string BOOL_PARSE_TEMPLATE = @"				bool {PROPERTY_LOWER};
				{SEARCH_NAME}.{PROPERTY} = bool.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER}) ? {PROPERTY_LOWER} : false;";

        private const string DECIMAL_PARSE_TEMPLATE = @"				decimal {PROPERTY_LOWER};
				{SEARCH_NAME}.{PROPERTY} = decimal.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER}) ? {PROPERTY_LOWER} : 0;";


		private const string ITEM_TEMPLATE =
			@"		
			if (request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}] != null) {
{PARSE_TEMPLATE}
			}
";

		private const string LONG_PARSE_TEMPLATE = @"				long {PROPERTY_LOWER};
				{SEARCH_NAME}.{PROPERTY} = long.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER}) ? {PROPERTY_LOWER} : 0;";

		private const string DOUBLE_PARSE_TEMPLATE = @"				double {PROPERTY_LOWER};
				{SEARCH_NAME}.{PROPERTY} = double.TryParse(request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}], out {PROPERTY_LOWER}) ? {PROPERTY_LOWER} : 0;";


		private const string NESTED_CLASS_TEMPLATE =
			@"		/// <summary>
		/// Creates a new <c>{CLASS_NAME}</c> from the request.
		/// </summary>
		/// <param name=""request"">Request to create the {CLASS_NAME} from.</param>
		/// <returns>A populated {CLASS_NAME} object.</returns>
		public static {CLASS_NAME} Create{CLASS_NAME}(MvcRequest request)
		{


			return new {CLASS_NAME}()
			                         {
			                         	//TODO {INIT_PARAMS}
			                         };
		}


		/// <summary>
		/// Populates the <c>{CLASS_NAME}</c> with the values from the request.
		/// </summary>
		/// <param name=""request"">Request to populate the {CLASS_NAME} from.</param>
		/// <param name=""{SEARCH_NAME}"">{CLASS_NAME} to populate</param>
		/// <returns>Populated from the request {CLASS_NAME} object.</returns>
		public static {CLASS_NAME} Populate(MvcRequest request,
		                            {CLASS_NAME} {SEARCH_NAME})
		{

{POPULATE_PARAMS}

			return {SEARCH_NAME};
		}
";

		private const string STRING_PARSE_TEMPLATE = @"				{SEARCH_NAME}.{PROPERTY} = request[ParameterNames.{CLASS_NAME}.Field.{PROPERTY_UPPER}];";

		public DeserializeGenerator() {}


		public DeserializeGenerator(Assembly assembly)
		{
			this.Assembly = assembly;
		}


		public Assembly Assembly { get; set; }


		public void Execute(IEnumerable<string> selectedClassNames)
		{
			string nestedClasses = "";

			string nameSpace = "";

			string modelNameSpace = "";

			foreach (string fullName in selectedClassNames) {
				//create a new template string
				string singleClass = NESTED_CLASS_TEMPLATE;

				Type classType = this.Assembly.GetType(fullName);
				string className = classType.Name;

				nameSpace = Utilities.GetSupportRequestNameSpace(classType.Namespace);

				modelNameSpace = Utilities.GetModelNameSpace(classType.Namespace);

				singleClass = singleClass.Replace("{CLASS_NAME}", className);

				singleClass = singleClass.Replace("{POPULATE_PARAMS}", this.GetProperties(className, classType));

				singleClass = singleClass.Replace("{SEARCH_NAME}", className.ToLower());

				nestedClasses += singleClass + Environment.NewLine + Environment.NewLine;
			}

			string classFile = DESERILIZE_CLASS_WRAPPER.Replace("{NESTED_CLASSES}", nestedClasses);

			classFile = classFile.Replace("{NAMESPACE}", nameSpace);

			classFile = classFile.Replace("{NAMESPACE_MODEL}", modelNameSpace);

			Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + DAO_SUPPORT_DIRECTORY);

			TextWriter writer =
				new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + DAO_SUPPORT_DIRECTORY + "Deserialize.cs");

			writer.Write(classFile);

			writer.Flush();
			writer.Close();
		}


		private string GetProperties(string className,
		                             Type type)
		{
			string properties = "";


			foreach (MemberInfo member in type.GetMembers()) {
				if (member.MemberType == MemberTypes.Property) {
					if (member.Name != "Id" && member.Name != "Version" && Utilities.IsPrimitive(Utilities.GetRealTypeFromMemberProperty(member))) {
						properties += this.GetProperty(member, className) + Environment.NewLine + Environment.NewLine;
					}
				}
			}

			return properties;
		}


		private string GetProperty(MemberInfo member,
		                           string className)
		{
			Type t = Utilities.GetRealTypeFromMemberProperty(member);
			string parseTemplate = STRING_PARSE_TEMPLATE;

			if (t == typeof (int)) {
				parseTemplate = INT_PARSE_TEMPLATE;
			} else if (t == typeof (float)) {
				parseTemplate = FLOAT_PARSE_TEMPLATE;
			} else if (t == typeof (long)) {
				parseTemplate = LONG_PARSE_TEMPLATE;
			} else if (t == typeof (DateTime)) {
				parseTemplate = DATETIME_PARSE_TEMPLATE;
			} else if(t == typeof(double)) {
				parseTemplate = DOUBLE_PARSE_TEMPLATE;
			} else if(t == typeof(bool)) {
				parseTemplate = BOOL_PARSE_TEMPLATE;
			} else if(t == typeof(decimal))
			{
			    parseTemplate = DECIMAL_PARSE_TEMPLATE;
			}

			string template = ITEM_TEMPLATE.Replace("{PARSE_TEMPLATE}", parseTemplate);

			return this.ReplacePlaceHolders(template, member.Name, className.ToLower(), className);
		}


		private string ReplacePlaceHolders(
			string template,
			string name,
			string searchName,
			string className)
		{
			string property = template;

			property = property.Replace("{PROPERTY}", name);

			property = property.Replace("{PROPERTY_UPPER}", name.ToUpper());

			property = property.Replace("{PROPERTY_LOWER}", name.ToLower());

			property = property.Replace("{SEARCH_NAME}", searchName);

			property = property.Replace("{CLASS_NAME}", className);

			return property;
		}
	}
}